<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

</body>
<script>
    //【1】数组的浅拷贝{常用的一个数组复制技巧，concat本质上只是一个浅拷贝方法}
    // 如果是数组，我们可以利用数组的一些方法比如：slice、concat 返回一个新数组的特性来实现拷贝。
    var arr = ['old', 1, true, null, undefined];
    var new_arr = arr.concat();
    new_arr[0] = 'new';
    console.log(arr) // ["old", 1, true, null, undefined]
    console.log(new_arr) // ["new", 1, true, null, undefined]

    var new_arr = arr.slice();
    // 但是如果数组嵌套了对象或者数组的话，比如：
    var arr = [{
            old: 'old'
        },
        ['old']
    ];
    var new_arr = arr.concat();
    arr[0].old = 'new';
    arr[1][0] = 'new';
    console.log(arr) // [{old: 'new'}, ['new']]
    console.log(new_arr) // [{old: 'new'}, ['new']]

    // 如果数组元素是基本类型，就会拷贝一份，互不影响，而如果是对象或者数组，
    // 就会只拷贝对象和数组的引用，这样我们无论在新旧数组进行了修改，两者都会发生变化。

    // 我们把这种复制引用的拷贝方法称之为浅拷贝，与之对应的就是深拷贝，深拷贝就是指完全的拷贝一个对象，
    // 即使嵌套了对象，两者也相互分离，修改一个对象的属性，也不会影响另一个。

    // 所以我们可以看出使用 concat 和 slice 是一种浅拷贝。

    //【2】那如何深拷贝一个数组呢？这里介绍一个技巧，不仅适用于数组还适用于对象！那就是：
    var arr = ['old', 1, true, ['old1', 'old2'], {
        old: 1
    }];
    //【注意】这是个很实用的技巧
    // JSON.stringify是个将js对象转换为字符串的方法
    // 而JSON.parse是个将json数据转换为js对象的方法
    var new_arr = JSON.parse(JSON.stringify(arr));
    console.log(new_arr);
    // 是一个简单粗暴的好方法，就是有一个问题，不能拷贝函数，我们做个试验：

    var arr = [function() {
        console.log(a)
    }, {
        b: function() {
            console.log(b)
        }
    }]
    var new_arr = JSON.parse(JSON.stringify(arr));
    console.log(new_arr);
    // 我们会发现 new_arr 变成了一个数组，第一项是null，第二项是空对象
    //【3】数组和对象的浅拷贝的实现
    // 以上三个方法 concat、slice、JSON.stringify 都算是技巧类，可以根据实际项目情况选择使用，
    // 接下来我们思考下如何实现一个对象或者数组的浅拷贝。

    // 想一想，好像很简单，遍历对象，然后把属性和属性值都放在一个新的对象不就好了~
    // 嗯，就是这么简单，注意几个小点就可以了：
    var shallowCopy = function(obj) {
        debugger
        // 只拷贝对象
        if (typeof obj !== 'object') return;
        // 根据obj的类型判断是新建一个数组还是对象
        var newObj = obj instanceof Array ? [] : {};
        // 遍历obj，并且判断是obj的属性才拷贝
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = obj[key];
            }
        }
        return newObj;
    };
    console.log(shallowCopy([1, 2]));
    //【4】数组和对象的深拷贝的实现
    // 那如何实现一个深拷贝呢？说起来也好简单，我们在拷贝的时候判断一下属性值的类型，
    // 如果是对象，我们递归调用深拷贝函数不就好了
    var deepCopy = function(obj) {
        if (typeof obj !== 'object') return;
        var newObj = obj instanceof Array ? [] : {};
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
            }
        }
        return newObj;
    }

    //【附加】尽管使用深拷贝会完全的克隆一个新对象，不会产生副作用，但是深拷贝因为使用递归，
    // 性能会不如浅拷贝，在开发中，还是要根据实际情况进行选择。
</script>

</html>